/**
 * @file order_server.h
 * @brief 订单服务器的头文件
 * 
 * @details 该文件定义了OrderServer类，负责处理客户端连接、接收客户端请求并发送响应。
 * 订单服务器是交易所系统的前端，负责与客户端进行通信，并将请求转发给匹配引擎。
 * 
 * @author 原作者
 * @date 2023
 */

#pragma once

#include <functional>

#include "common/thread_utils.h"
#include "common/macros.h"
#include "common/tcp_server.h"

#include "order_server/client_request.h"
#include "order_server/client_response.h"
#include "order_server/fifo_sequencer.h"

namespace Exchange {
  /**
   * @class OrderServer
   * @brief 订单服务器类
   * 
   * @details 该类负责管理客户端连接、接收客户端请求并将其转发给匹配引擎，以及将匹配引擎的响应发送回客户端。
   * 订单服务器使用TCP协议与客户端通信，并使用FIFO序列器确保请求按照接收时间顺序处理。
   * 订单服务器还负责维护客户端连接状态和序列号管理，确保消息的可靠传输。
   */
  class OrderServer {
  public:
    /**
     * @brief 构造函数
     * 
     * @details 初始化订单服务器，设置客户端请求和响应队列，配置网络接口和端口。
     * 同时初始化序列号管理和客户端连接映射。
     * 
     * @param client_requests 客户端请求无锁队列指针，用于将请求转发给匹配引擎
     * @param client_responses 客户端响应无锁队列指针，用于接收匹配引擎的响应
     * @param iface 网络接口名称
     * @param port 监听端口号
     */
    OrderServer(ClientRequestLFQueue *client_requests, ClientResponseLFQueue *client_responses, const std::string &iface, int port);

    /**
     * @brief 析构函数
     * 
     * @details 停止订单服务器并等待资源释放。
     */
    ~OrderServer();

    /**
     * @brief 启动订单服务器
     * 
     * @details 启动订单服务器的主线程，开始监听指定的网络接口和端口，
     * 等待客户端连接并处理请求。
     * 
     * @return void
     */
    auto start() -> void;

    /**
     * @brief 停止订单服务器
     * 
     * @details 通过设置run_标志为false，使订单服务器的主线程退出循环并结束运行。
     * 
     * @return void
     */
    auto stop() -> void;

    /**
     * @brief 订单服务器的主运行循环
     * 
     * @details 该方法是订单服务器的主运行循环，负责接受新的客户端连接、
     * 接收客户端请求并将匹配引擎的响应发送回客户端。
     * 循环内部包含以下步骤：
     * 1. 调用TCP服务器的poll方法检查新连接
     * 2. 调用sendAndRecv方法发送和接收数据
     * 3. 处理来自匹配引擎的响应，并将其发送给相应的客户端
     * 
     * @return void
     * @note 该方法在单独的线程中运行，直到run_标志被设置为false
     */
    auto run() noexcept {
      // 记录方法开始执行的日志
      logger_.log("%:% %() %\n", __FILE__, __LINE__, __FUNCTION__, Common::getCurrentTimeStr(&time_str_));
      
      // 主循环，当run_为true时持续运行
      while (run_) {
        // 检查新的客户端连接
        tcp_server_.poll();

        // 发送和接收数据
        tcp_server_.sendAndRecv();

        // 处理来自匹配引擎的响应，并将其发送给相应的客户端
        for (auto client_response = outgoing_responses_->getNextToRead(); outgoing_responses_->size() && client_response; client_response = outgoing_responses_->getNextToRead()) {
          // 测量从无锁队列读取响应的时间
          TTT_MEASURE(T5t_OrderServer_LFQueue_read, logger_);

          // 获取当前客户端的下一个序列号
          auto &next_outgoing_seq_num = cid_next_outgoing_seq_num_[client_response->client_id_];
          // 记录处理客户端响应的日志
          logger_.log("%:% %() % Processing cid:% seq:% %\n", __FILE__, __LINE__, __FUNCTION__, Common::getCurrentTimeStr(&time_str_),
                      client_response->client_id_, next_outgoing_seq_num, client_response->toString());

          // 确保客户端的TCP连接存在
          ASSERT(cid_tcp_socket_[client_response->client_id_] != nullptr,
                 "Dont have a TCPSocket for ClientId:" + std::to_string(client_response->client_id_));
          
          // 开始测量发送数据的时间
          START_MEASURE(Exchange_TCPSocket_send);
          // 首先发送序列号
          cid_tcp_socket_[client_response->client_id_]->send(&next_outgoing_seq_num, sizeof(next_outgoing_seq_num));
          // 然后发送响应内容
          cid_tcp_socket_[client_response->client_id_]->send(client_response, sizeof(MEClientResponse));
          // 结束测量发送数据的时间
          END_MEASURE(Exchange_TCPSocket_send, logger_);

          // 更新无锁队列的读取索引，表示已处理完当前响应
          outgoing_responses_->updateReadIndex();
          // 测量写入TCP的时间
          TTT_MEASURE(T6t_OrderServer_TCP_write, logger_);

          // 增加序列号，为下一个响应做准备
          ++next_outgoing_seq_num;
        }
      }
    }

    /**
     * @brief 从 TCP 接收缓冲区读取客户端请求
     * 
     * @details 该回调函数在TCP服务器接收到数据时被调用。它从接收缓冲区读取客户端请求，
     * 检查序列号是否连续，并将有效的请求转发给FIFO序列器。
     * 如果发现序列号不连续或客户端使用了不同的连接，将跳过该请求。
     * 
     * @param socket 接收数据的TCP套接字指针
     * @param rx_time 接收数据的时间戳，以纳秒为单位
     * @return void
     */
    auto recvCallback(TCPSocket *socket, Nanos rx_time) noexcept {
      // 测量 TCP 读取时间
      TTT_MEASURE(T1_OrderServer_TCP_read, logger_);
      // 记录接收到数据的日志
      logger_.log("%:% %() % Received socket:% len:% rx:%\n", __FILE__, __LINE__, __FUNCTION__, Common::getCurrentTimeStr(&time_str_),
                  socket->socket_fd_, socket->next_rcv_valid_index_, rx_time);

      // 检查接收缓冲区中是否有足够的数据构成一个完整的请求
      if (socket->next_rcv_valid_index_ >= sizeof(OMClientRequest)) {
        size_t i = 0;
        // 遍历接收缓冲区中的所有完整请求
        for (; i + sizeof(OMClientRequest) <= socket->next_rcv_valid_index_; i += sizeof(OMClientRequest)) {
          // 将缓冲区中的数据转换为客户端请求对象
          auto request = reinterpret_cast<const OMClientRequest *>(socket->inbound_data_.data() + i);
          // 记录接收到请求的日志
          logger_.log("%:% %() % Received %\n", __FILE__, __LINE__, __FUNCTION__, Common::getCurrentTimeStr(&time_str_), request->toString());

          // 如果是来自该客户端的第一个消息，记录客户端与套接字的映射关系
          if (UNLIKELY(cid_tcp_socket_[request->me_client_request_.client_id_] == nullptr)) { // first message from this ClientId.
            cid_tcp_socket_[request->me_client_request_.client_id_] = socket;
          }

          // 检查客户端是否使用了不同的连接发送请求
          if (cid_tcp_socket_[request->me_client_request_.client_id_] != socket) { // TODO - change this to send a reject back to the client.
            // 记录错误日志，客户端使用了不同的连接
            logger_.log("%:% %() % Received ClientRequest from ClientId:% on different socket:% expected:%\n", __FILE__, __LINE__, __FUNCTION__,
                        Common::getCurrentTimeStr(&time_str_), request->me_client_request_.client_id_, socket->socket_fd_,
                        cid_tcp_socket_[request->me_client_request_.client_id_]->socket_fd_);
            continue; // 跳过该请求
          }

          // 获取客户端的下一个期望序列号
          auto &next_exp_seq_num = cid_next_exp_seq_num_[request->me_client_request_.client_id_];
          // 检查序列号是否连续
          if (request->seq_num_ != next_exp_seq_num) { // TODO - change this to send a reject back to the client.
            // 记录错误日志，序列号不连续
            logger_.log("%:% %() % Incorrect sequence number. ClientId:% SeqNum expected:% received:%\n", __FILE__, __LINE__, __FUNCTION__,
                        Common::getCurrentTimeStr(&time_str_), request->me_client_request_.client_id_, next_exp_seq_num, request->seq_num_);
            continue; // 跳过该请求
          }

          // 更新下一个期望序列号
          ++next_exp_seq_num;

          // 开始测量添加客户端请求到FIFO序列器的时间
          START_MEASURE(Exchange_FIFOSequencer_addClientRequest);
          // 将请求添加到FIFO序列器
          fifo_sequencer_.addClientRequest(rx_time, request->me_client_request_);
          // 结束测量
          END_MEASURE(Exchange_FIFOSequencer_addClientRequest, logger_);
        }
        // 将未处理完的数据移动到缓冲区开头，以便下次处理
        memcpy(socket->inbound_data_.data(), socket->inbound_data_.data() + i, socket->next_rcv_valid_index_ - i);
        // 更新缓冲区中有效数据的长度
        socket->next_rcv_valid_index_ -= i;
      }
    }

    /**
     * @brief 完成所有TCP连接的数据读取后的回调函数
     * 
     * @details 该回调函数在TCP服务器完成所有连接的数据读取后被调用。
     * 它调用FIFO序列器的sequenceAndPublish方法，将收集到的客户端请求
     * 按接收时间排序，并发布到匹配引擎进行处理。
     * 
     * @return void
     */
    auto recvFinishedCallback() noexcept {
      // 开始测量序列化和发布请求的时间
      START_MEASURE(Exchange_FIFOSequencer_sequenceAndPublish);
      // 调用FIFO序列器的sequenceAndPublish方法，将请求排序并发送给匹配引擎
      fifo_sequencer_.sequenceAndPublish();
      // 结束测量
      END_MEASURE(Exchange_FIFOSequencer_sequenceAndPublish, logger_);
    }

    /// Deleted default, copy & move constructors and assignment-operators.
    OrderServer() = delete;

    OrderServer(const OrderServer &) = delete;

    OrderServer(const OrderServer &&) = delete;

    OrderServer &operator=(const OrderServer &) = delete;

    OrderServer &operator=(const OrderServer &&) = delete;

  private:
    /**
     * @brief 网络接口名称
     * 
     * @details 订单服务器监听的网络接口名称，如"eth0"或"lo"等。
     */
    const std::string iface_;
    
    /**
     * @brief 监听端口号
     * 
     * @details 订单服务器监听的TCP端口号，客户端通过该端口连接到订单服务器。
     */
    const int port_ = 0;

    /**
     * @brief 客户端响应无锁队列
     * 
     * @details 存储要发送给已连接客户端的响应消息的无锁队列。
     * 匹配引擎将响应写入该队列，订单服务器从该队列读取响应并发送给客户端。
     */
    ClientResponseLFQueue *outgoing_responses_ = nullptr;

    /**
     * @brief 运行标志
     * 
     * @details 控制订单服务器主循环是否继续运行的标志。
     * 当设置为false时，主循环将退出，订单服务器停止运行。
     */
    volatile bool run_ = false;

    /**
     * @brief 时间字符串缓冲区
     * 
     * @details 用于存储当前时间的字符串表示，主要用于日志记录。
     */
    std::string time_str_;
    
    /**
     * @brief 日志记录器
     * 
     * @details 用于记录订单服务器的操作和状态日志。
     */
    Logger logger_;

    /**
     * @brief 客户端发送序列号映射
     * 
     * @details 映射表，从客户端ID到下一个将要发送的响应序列号。
     * 用于确保发送给客户端的响应序列号连续递增。
     */
    std::array<size_t, ME_MAX_NUM_CLIENTS> cid_next_outgoing_seq_num_;

    /**
     * @brief 客户端接收序列号映射
     * 
     * @details 映射表，从客户端ID到下一个期望接收的请求序列号。
     * 用于检测序列号不连续的情况，确保请求按序列号顺序处理。
     */
    std::array<size_t, ME_MAX_NUM_CLIENTS> cid_next_exp_seq_num_;

    /**
     * @brief 客户端连接映射
     * 
     * @details 映射表，从客户端ID到对应的TCP套接字/客户端连接。
     * 用于跟踪每个客户端的连接状态，并在发送响应时使用。
     */
    std::array<Common::TCPSocket *, ME_MAX_NUM_CLIENTS> cid_tcp_socket_;

    /**
     * @brief TCP服务器实例
     * 
     * @details 用于监听新的客户端连接请求的TCP服务器实例。
     * 负责接受新连接、发送和接收数据。
     */
    Common::TCPServer tcp_server_;

    /**
     * @brief FIFO序列器
     * 
     * @details 负责确保客户端请求按照接收时间的顺序处理。
     * 它收集客户端请求，根据接收时间排序，然后将其发送给匹配引擎处理。
     */
    FIFOSequencer fifo_sequencer_;
  };
}
